package com.xiaomi.infra.galaxy.fds.client;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.TimeZone;
import java.util.UUID;
import javax.net.ssl.SSLContext;
import com.google.common.base.Preconditions;
import com.google.common.collect.LinkedListMultimap;
import com.google.gson.Gson;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import com.xiaomi.infra.galaxy.fds.Action;
import com.xiaomi.infra.galaxy.fds.Common;
import com.xiaomi.infra.galaxy.fds.SubResource;
import com.xiaomi.infra.galaxy.fds.auth.signature.SignAlgorithm;
import com.xiaomi.infra.galaxy.fds.auth.signature.Signer;
import com.xiaomi.infra.galaxy.fds.auth.signature.XiaomiHeader;
import com.xiaomi.infra.galaxy.fds.bean.BucketBean;
import com.xiaomi.infra.galaxy.fds.bean.GrantBean;
import com.xiaomi.infra.galaxy.fds.bean.GranteeBean;
import com.xiaomi.infra.galaxy.fds.bean.ObjectBean;
import com.xiaomi.infra.galaxy.fds.bean.OwnerBean;
import com.xiaomi.infra.galaxy.fds.client.credential.GalaxyFDSCredential;
import com.xiaomi.infra.galaxy.fds.client.exception.GalaxyException;
import com.xiaomi.infra.galaxy.fds.client.exception.GalaxyFDSClientException;
import com.xiaomi.infra.galaxy.fds.client.filter.FDSClientLogFilter;
import com.xiaomi.infra.galaxy.fds.client.filter.MetricsRequestFilter;
import com.xiaomi.infra.galaxy.fds.client.filter.MetricsResponseFilter;
import com.xiaomi.infra.galaxy.fds.client.metrics.ClientMetrics;
import com.xiaomi.infra.galaxy.fds.client.metrics.MetricsCollector;
import com.xiaomi.infra.galaxy.fds.client.model.FDSBucket;
import com.xiaomi.infra.galaxy.fds.client.model.FDSMd5InputStream;
import com.xiaomi.infra.galaxy.fds.client.model.FDSObject;
import com.xiaomi.infra.galaxy.fds.client.model.FDSObjectInputStream;
import com.xiaomi.infra.galaxy.fds.client.model.FDSObjectListing;
import com.xiaomi.infra.galaxy.fds.client.model.FDSObjectSummary;
import com.xiaomi.infra.galaxy.fds.client.model.Owner;
import com.xiaomi.infra.galaxy.fds.model.AccessControlList;
import com.xiaomi.infra.galaxy.fds.model.FDSObjectMetadata;
import com.xiaomi.infra.galaxy.fds.model.HttpMethod;
import com.xiaomi.infra.galaxy.fds.result.AccessControlPolicy;
import com.xiaomi.infra.galaxy.fds.result.InitMultipartUploadResult;
import com.xiaomi.infra.galaxy.fds.result.ListAllAuthorizedBucketsResult;
import com.xiaomi.infra.galaxy.fds.result.ListAllBucketsResult;
import com.xiaomi.infra.galaxy.fds.result.ListDomainMappingsResult;
import com.xiaomi.infra.galaxy.fds.result.ListObjectsResult;
import com.xiaomi.infra.galaxy.fds.result.PutObjectResult;
import com.xiaomi.infra.galaxy.fds.result.QuotaPolicy;
import com.xiaomi.infra.galaxy.fds.result.UploadPartResult;
import com.xiaomi.infra.galaxy.fds.result.UploadPartResultList;
public class GalaxyFDSClient implements GalaxyFDS {
public static final String ORG_ID_PARAM = "orgId";
private final GalaxyFDSCredential credential;
private final FDSClientConfiguration fdsConfig;
private MetricsCollector metricsCollector;
private String delimiter = "/";
private final Random random = new Random();
private final String clientId = UUID.randomUUID().toString().substring(0, 8);
private HttpClient httpClient;
private FDSClientLogFilter logFilter = new FDSClientLogFilter();
private PoolingHttpClientConnectionManager connectionManager;
// TODO(wuzesheng) Make the authenticator configurable and let the
// authenticator supply sign algorithm and generate signature
private static SignAlgorithm SIGN_ALGORITHM = SignAlgorithm.HmacSHA1;
public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(
"EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
static {
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT"));
}
private static final Log LOG = LogFactory.getLog(GalaxyFDSClient.class);
public GalaxyFDSClient(GalaxyFDSCredential credential,
FDSClientConfiguration fdsConfig) {
this.credential = credential;
this.fdsConfig = fdsConfig;
init();
}
private void init() {
if (fdsConfig.isApacheConnectorEnabled()) {
LOG.warn("Apache Connector not supported");
}
httpClient = createHttpClient(this.fdsConfig);
if (fdsConfig.isMetricsEnabled()) {
metricsCollector = new MetricsCollector(this);
}
}
private HttpClient createHttpClient(FDSClientConfiguration config) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(config.getConnectionTimeoutMs())
.setSocketTimeout(config.getSocketTimeoutMs())
.build();
RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder.create();
registryBuilder.register("http", new PlainConnectionSocketFactory());
if (config.isHttpsEnabled()) {
SSLContext sslContext = SSLContexts.createSystemDefault();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslContext,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
registryBuilder.register("https", sslsf);
}
connectionManager = new PoolingHttpClientConnectionManager(registryBuilder.build());
connectionManager.setDefaultMaxPerRoute(config.getMaxConnection());
connectionManager.setMaxTotal(config.getMaxConnection());
HttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig)
.setRetryHandler(new DefaultHttpRequestRetryHandler(3, false))
.build();
return httpClient;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
private HttpUriRequest prepareRequestMethod(URI uri,
HttpMethod method, ContentType contentType, FDSObjectMetadata metadata,
HashMap<String, String> params, Map<String, List<Object>> headers,
HttpEntity requestEntity) throws GalaxyFDSClientException {
if (params != null) {
URIBuilder builder = new URIBuilder(uri);
for (Entry<String, String> param : params.entrySet()) {
builder.addParameter(param.getKey(), param.getValue());
}
try {
uri = builder.build();
} catch (URISyntaxException e) {
throw new GalaxyFDSClientException("Invalid param: " + params.toString(), e);
}
}
if (headers == null)
headers = new HashMap<String, List<Object>>();
Map<String, Object> h = prepareRequestHeader(uri, method, contentType, metadata);
for (Entry<String, Object> hIte : h.entrySet()) {
String key = hIte.getKey();
if (!headers.containsKey(key)) {
headers.put(key, new ArrayList<Object>());
}
headers.get(key).add(hIte.getValue());
}
HttpUriRequest httpRequest;
switch (method) {
case PUT:
HttpPut httpPut = new HttpPut(uri);
if (requestEntity != null)
httpPut.setEntity(requestEntity);
httpRequest = httpPut;
break;
case GET:
httpRequest = new HttpGet(uri);
break;
case DELETE:
httpRequest = new HttpDelete(uri);
break;
case HEAD:
httpRequest = new HttpHead(uri);
break;
case POST:
HttpPost httpPost = new HttpPost(uri);
if (requestEntity != null)
httpPost.setEntity(requestEntity);
httpRequest = httpPost;
break;
default:
throw new GalaxyFDSClientException("Method " + method.name() +
" not supported");
}
for (Entry<String, List<Object>> header : headers.entrySet()) {
String key = header.getKey();
if (key == null || key.isEmpty())
continue;
for (Object obj : header.getValue()) {
if (obj == null)
continue;
httpRequest.addHeader(header.getKey(), obj.toString());
}
}
return httpRequest;
}
@Override
public List<FDSBucket> listBuckets() throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), "", (SubResource[]) null);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.ListBuckets);
ListAllBucketsResult result = (ListAllBucketsResult) processResponse(response, ListAllBucketsResult.class,
"list buckets");
ArrayList<FDSBucket> buckets = new ArrayList<FDSBucket>();
if (result != null) {
OwnerBean owner = result.getOwner();
for (BucketBean b : result.getBuckets()) {
FDSBucket bucket = new FDSBucket(b.getName());
bucket.setOwner(new Owner(owner.getId(), owner.getDisplayName()));
buckets.add(bucket);
}
}
return buckets;
}
@Override
public List<FDSBucket> listAuthorizedBuckets() throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), "", (SubResource[]) null);
HashMap<String, String> params = new LinkedHashMap<String, String>();
params.put("authorizedBuckets", "");
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, params, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.ListAuthorizedBuckets);
ListAllAuthorizedBucketsResult result = (ListAllAuthorizedBucketsResult) processResponse(response,
ListAllAuthorizedBucketsResult.class, "list authorized buckets");
ArrayList<FDSBucket> buckets = new ArrayList<FDSBucket>();
if (result != null) {
for (BucketBean b : result.getBuckets()) {
FDSBucket bucket = new FDSBucket(b.getName());
bucket.setOwner(new Owner(b.getOrgId(), b.getOrgId()));
buckets.add(bucket);
}
}
return buckets;
}
private <T> Object processResponse(HttpResponse response, Class<T> c,
String purposeStr) throws GalaxyFDSClientException {
HttpEntity httpEntity = response.getEntity();
int statusCode = response.getStatusLine().getStatusCode();
try {
if (statusCode == HttpStatus.SC_OK) {
if (c != null) {
Gson gson = new Gson();
Reader reader = new InputStreamReader(httpEntity.getContent());
T entityVal = gson.fromJson(reader, c);
return entityVal;
}
return null;
} else {
String errorMsg = formatErrorMsg(purposeStr, response);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg);
}
} catch (IOException e) {
String errorMsg = formatErrorMsg("read response entity", e);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg, e);
} finally {
closeResponseEntity(response);
}
}
private HttpResponse executeHttpRequest(HttpUriRequest httpRequest,
Action action) throws GalaxyFDSClientException {
HttpContext context = null;
if (fdsConfig.isMetricsEnabled()) {
context = new BasicHttpContext();
context.setAttribute(Common.ACTION, httpRequest);
context.setAttribute(Common.ACTION, action);
context.setAttribute(Common.METRICS_COLLECTOR, metricsCollector);
MetricsRequestFilter requestFilter = new MetricsRequestFilter();
try {
requestFilter.filter(context);
} catch (IOException e) {
LOG.error("fail to call request filter", e);
}
}
HttpResponse response = null;
try {
try {
response = httpClient.execute(httpRequest);
} catch (IOException e) {
LOG.error("http request failed", e);
throw new GalaxyFDSClientException(e.getMessage(), e);
}
return response;
} finally {
if (fdsConfig.isMetricsEnabled()) {
try {
logFilter.filter(httpRequest, response);
} catch (IOException e) {
LOG.error("log filter failed", e);
}
MetricsResponseFilter responseFilter = new MetricsResponseFilter();
try {
responseFilter.filter(context);
} catch (IOException e) {
LOG.error("fail to call response filter", e);
}
}
}
}
@Override
public void createBucketUnderOrg(String org, String bucketName)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
StringEntity requestEntity = getJsonStringEntity("{}", ContentType.APPLICATION_JSON);
HashMap<String, String> params = new HashMap<String, String>();
params.put(ORG_ID_PARAM, org);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
ContentType.APPLICATION_JSON, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutBucket);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
String errorMsg = formatErrorMsg("create bucket [" + bucketName + "]", response);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg);
}
} finally {
closeResponseEntity(response);
}
}
@Override
public void createBucket(String bucketName) throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
StringEntity requestEntity = getJsonStringEntity("{}", ContentType.APPLICATION_JSON);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
ContentType.APPLICATION_JSON, null, null, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutBucket);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
String errorMsg = formatErrorMsg("create bucket [" + bucketName + "]", response);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg);
}
} finally {
closeResponseEntity(response);
}
}
private void closeResponseEntity(HttpResponse response) {
if (response == null)
return;
HttpEntity entity = response.getEntity();
if (entity != null && entity.isStreaming())
try {
entity.getContent().close();
} catch (IOException e) {
LOG.error(formatErrorMsg("close response entity", e));
}
}
@Override
public void deleteBucket(String bucketName) throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.DELETE, null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutBucket);
processResponse(response, null, "delete bucket [" + bucketName + "]");
}
@Override
public void getBucket(String bucketName) throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.GetBucketMeta);
processResponse(response, null, "get bucket [" + bucketName + "]");
}
@Override
public boolean doesBucketExist(String bucketName)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.HEAD, null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.HeadBucket);
int statusCode = response.getStatusLine().getStatusCode();
try {
if (statusCode == HttpStatus.SC_OK)
return true;
else if (statusCode == HttpStatus.SC_NOT_FOUND)
return false;
else {
String errorMsg = formatErrorMsg("check bucket [" + bucketName + "] existence", response);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg);
}
} finally {
closeResponseEntity(response);
}
}
private String getResponseEntityPhrase(HttpResponse response) {
try {
InputStream inputStream = response.getEntity().getContent();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] data = new byte[1024];
for (int count; (count = inputStream.read(data, 0, 1024)) != -1; )
outputStream.write(data, 0, count);
String reason = outputStream.toString();
if (reason == null || reason.isEmpty())
return response.getStatusLine().getReasonPhrase();
return reason;
} catch (Exception e) {
LOG.error("Fail to get entity string");
return response.getStatusLine().getReasonPhrase();
}
}
@Override
public AccessControlList getBucketAcl(String bucketName)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, SubResource.ACL);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.GetBucketACL);
AccessControlPolicy acp = (AccessControlPolicy) processResponse(response,
AccessControlPolicy.class, "get bucket [" + bucketName + "] acl");
return acpToAcl(acp);
}
@Override
public void setBucketAcl(String bucketName, AccessControlList acl)
throws GalaxyFDSClientException {
Preconditions.checkNotNull(acl);
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, SubResource.ACL);
ContentType contentType = ContentType.APPLICATION_JSON;
AccessControlPolicy acp = aclToAcp(acl);
StringEntity requestEntity = getJsonStringEntity(acp, contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT, contentType, null, null, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutBucketACL);
processResponse(response, null, "set bucket [" + bucketName + "] acl");
}
@Override
public QuotaPolicy getBucketQuota(String bucketName)
throws GalaxyFDSClientException {
Preconditions.checkNotNull(bucketName);
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, SubResource.QUOTA);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.GetBucketQuota);
QuotaPolicy quotaPolicy = (QuotaPolicy) processResponse(response,
QuotaPolicy.class, "get bucket [" + bucketName + "] quota");
return quotaPolicy;
}
@Override
public void setBucketQuota(String bucketName, QuotaPolicy quotaPolicy)
throws GalaxyFDSClientException {
Preconditions.checkNotNull(quotaPolicy);
Preconditions.checkNotNull(bucketName);
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, SubResource.QUOTA);
ContentType contentType = ContentType.APPLICATION_JSON;
HttpEntity requestEntity = getJsonStringEntity(quotaPolicy, contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT, contentType, null, null, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutBucketQuota);
processResponse(response, null, "set bucket [" + bucketName + "] quota");
}
@Override
public FDSObjectListing listObjects(String bucketName)
throws GalaxyFDSClientException {
return listObjects(bucketName, "", this.delimiter);
}
@Override
public FDSObjectListing listObjects(String bucketName, String prefix)
throws GalaxyFDSClientException {
return listObjects(bucketName, prefix, this.delimiter);
}
@Override
public FDSObjectListing listObjects(String bucketName, String prefix,
String delimiter) throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("prefix", prefix);
params.put("delimiter", delimiter);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, params, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.ListObjects);
ListObjectsResult listObjectsResult = (ListObjectsResult) processResponse(response, ListObjectsResult.class, "list objects under bucket [" + bucketName + "] with prefix [" + prefix + "]");
return getObjectListing(listObjectsResult);
}
@Override
public FDSObjectListing listTrashObjects(String prefix, String delimiter)
throws GalaxyFDSClientException {
return listObjects(Common.TRASH_BUCKET_NAME, prefix, delimiter);
}
@Override
public FDSObjectListing listNextBatchOfObjects(
FDSObjectListing previousObjectListing) throws GalaxyFDSClientException {
if (!previousObjectListing.isTruncated()) {
LOG.warn("The previous listObjects() response is complete, " +
"call of listNextBatchOfObjects() will be ingored");
return null;
}
String bucketName = previousObjectListing.getBucketName();
String prefix = previousObjectListing.getPrefix();
String delimiter = previousObjectListing.getDelimiter();
String marker = previousObjectListing.getNextMarker();
int maxKeys = previousObjectListing.getMaxKeys();
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("prefix", prefix);
params.put("delimiter", delimiter);
params.put("marker", marker);
params.put("maxKeys", Integer.toString(maxKeys));
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, params, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.ListObjects);
ListObjectsResult listObjectsResult = (ListObjectsResult) processResponse(response,
ListObjectsResult.class,
"list next batch of objects under bucket [" + bucketName + "]" +
" with prefix [" + prefix + "], marker [" + marker + "]");
return getObjectListing(listObjectsResult);
}
@Override
public PutObjectResult putObject(String bucketName, String objectName,
File file) throws GalaxyFDSClientException {
FileInputStream stream = null;
try {
stream = new FileInputStream(file);
return putObject(bucketName, objectName, stream, file.length(), null);
} catch (FileNotFoundException e) {
String errorMsg = "File not found, file=" + file.getName();
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg, e);
} finally {
closeInputStream(stream);
}
}
private PutObjectResult putObject(String bucketName, String objectName,
InputStream input, long contentLength, FDSObjectMetadata metadata)
throws GalaxyFDSClientException {
ContentType contentType = ContentType.APPLICATION_OCTET_STREAM;
if (metadata != null && metadata.getContentType() != null) {
contentType = ContentType.create(metadata.getContentType());
}
if (fdsConfig.isMd5CalculateEnabled()) {
if (metadata == null) {
metadata = new FDSObjectMetadata();
}
metadata.addHeader(XiaomiHeader.MD5_ATTACHED_STREAM.getName(), "1");
try {
input = new FDSMd5InputStream(input);
} catch (NoSuchAlgorithmException e) {
throw new GalaxyFDSClientException("Cannot init md5", e);
}
}
URI uri = formatUri(fdsConfig.getUploadBaseUri(), bucketName + "/"
+ objectName, (SubResource[]) null);
InputStreamEntity requestEntity = getInputStreamRequestEntity(input, contentType, contentLength);
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.PUT, contentType, metadata, null, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutObject);
PutObjectResult putObjectResult = (PutObjectResult) processResponse(response,
PutObjectResult.class,
"put object [" + objectName + "] to bucket [" + bucketName + "]");
return putObjectResult;
}
@Override
public PutObjectResult putObject(String bucketName, String objectName,
InputStream input, FDSObjectMetadata metadata)
throws GalaxyFDSClientException {
return putObject(bucketName, objectName, input, -1, metadata);
}
private PutObjectResult postObject(String bucketName, InputStream input,
long contentLen, FDSObjectMetadata metadata) throws GalaxyFDSClientException {
ContentType contentType = ContentType.APPLICATION_OCTET_STREAM;
if (metadata != null && metadata.getContentType() != null) {
contentType = ContentType.create(metadata.getContentType());
}
if (fdsConfig.isMd5CalculateEnabled()) {
if (metadata == null) {
metadata = new FDSObjectMetadata();
}
metadata.addHeader(XiaomiHeader.MD5_ATTACHED_STREAM.getName(), "1");
try {
input = new FDSMd5InputStream(input);
} catch (NoSuchAlgorithmException e) {
throw new GalaxyFDSClientException("Cannot init md5", e);
}
}
URI uri = formatUri(fdsConfig.getUploadBaseUri(), bucketName + "/",
(SubResource[]) null);
InputStreamEntity requestEntity = getInputStreamRequestEntity(input, contentType, contentLen);
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.POST, contentType, metadata, null, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PostObject);
PutObjectResult putObjectResult = (PutObjectResult) processResponse(response,
PutObjectResult.class,
"post object to bucket [" + bucketName + "]");
return putObjectResult;
}
@Override
public PutObjectResult postObject(String bucketName, File file)
throws GalaxyFDSClientException {
FileInputStream stream = null;
try {
stream = new FileInputStream(file);
return postObject(bucketName, stream, file.length(), null);
} catch (FileNotFoundException e) {
String errorMsg = "File not found, file=" + file.getName();
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg, e);
} finally {
closeInputStream(stream);
}
}
@Override
public PutObjectResult postObject(String bucketName, InputStream input,
FDSObjectMetadata metadata) throws GalaxyFDSClientException {
return postObject(bucketName, input, -1, metadata);
}
@Override
public FDSObject getObject(String bucketName, String objectName)
throws GalaxyFDSClientException {
// start from position 0 by default
return getObject(bucketName, objectName, 0);
}
@Override
public FDSObject getObject(String bucketName, String objectName, long pos)
throws GalaxyFDSClientException {
if (pos < 0) {
String errorMsg = "get object " + objectName + " from bucket "
+ bucketName + " failed, reason=invalid seek position:" + pos;
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg);
}
URI uri = formatUri(fdsConfig.getDownloadBaseUri(), bucketName + "/"
+ objectName, (SubResource[]) null);
Map<String, List<Object>> headers = new HashMap<String, List<Object>>();
if (pos > 0) {
List<Object> objects = new ArrayList<Object>();
objects.add("bytes=" + pos + "-");
headers.put(Common.RANGE, objects);
}
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, null, headers, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.GetObject);
HttpEntity httpEntity = response.getEntity();
FDSObject rtnObject = null;
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK || statusCode == HttpStatus.SC_PARTIAL_CONTENT) {
FDSObjectSummary summary = new FDSObjectSummary();
summary.setBucketName(bucketName);
summary.setObjectName(objectName);
summary.setSize(httpEntity.getContentLength());
FDSObjectInputStream stream = new FDSObjectInputStream(httpEntity);
rtnObject = new FDSObject();
rtnObject.setObjectSummary(summary);
rtnObject.setObjectContent(stream);
rtnObject.setObjectMetadata(FDSObjectMetadata.parseObjectMetadata(
headerArray2MultiValuedMap(response.getAllHeaders())));
return rtnObject;
} else {
String errorMsg = formatErrorMsg("get object [" + objectName + "] from bucket [" + bucketName + "]", response);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg);
}
} catch (IOException e) {
String errorMsg = formatErrorMsg("read entity stream", e);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg, e);
} finally {
if (rtnObject == null) {
closeResponseEntity(response);
}
}
}
@Override
public FDSObjectMetadata getObjectMetadata(String bucketName,
String objectName) throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
SubResource.METADATA);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.GetObjectMetadata);
try {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
FDSObjectMetadata metadata = FDSObjectMetadata.parseObjectMetadata(
headerArray2MultiValuedMap(response.getAllHeaders()));
return metadata;
} else {
String errorMsg = formatErrorMsg("get metadata for object [" + objectName +
"] under bucket [" + bucketName + "]", response);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg);
}
} finally {
closeResponseEntity(response);
}
}
@Override
public AccessControlList getObjectAcl(String bucketName, String objectName)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
SubResource.ACL);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.GET, null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.GetObjectACL);
AccessControlPolicy acp = (AccessControlPolicy) processResponse(response,
AccessControlPolicy.class,
"get acl for object [" + objectName + "] under bucket [" + bucketName + "]");
return acpToAcl(acp);
}
@Override
public void setObjectAcl(String bucketName, String objectName,
AccessControlList acl) throws GalaxyFDSClientException {
Preconditions.checkNotNull(acl);
AccessControlPolicy acp = aclToAcp(acl);
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
SubResource.ACL);
StringEntity requestEntity = getJsonStringEntity(acp, ContentType.APPLICATION_JSON);
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.PUT,
ContentType.APPLICATION_JSON, null, null, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutObjectACL);
processResponse(response, null, "set acl for object [" +
objectName + "] under bucket [" + bucketName + "]");
}
@Override
public void deleteObjectAcl(String bucketName, String objectName,
AccessControlList acl) throws GalaxyFDSClientException {
Preconditions.checkNotNull(acl);
AccessControlPolicy acp = aclToAcp(acl);
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
SubResource.ACL);
HashMap<String, String> params = new HashMap<String, String>();
params.put("action", "delete");
ContentType contentType = ContentType.APPLICATION_JSON;
StringEntity requestEntity = getJsonStringEntity(acp, ContentType.APPLICATION_JSON);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.DeleteObjectACL);
processResponse(response, null, "delete acl for object [" + objectName + "] under bucket ["
+ bucketName + "]");
}
@Override
public boolean doesObjectExist(String bucketName, String objectName)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
(SubResource[]) null);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.HEAD,
null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.HeadObject);
int statusCode = response.getStatusLine().getStatusCode();
try {
if (statusCode == HttpStatus.SC_OK)
return true;
else if (statusCode == HttpStatus.SC_NOT_FOUND)
return false;
else {
String errorMsg = formatErrorMsg("check existence of object [" + objectName +
"] under bucket [" + bucketName + "]", response);
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg);
}
} finally {
closeResponseEntity(response);
}
}
@Override
public void deleteObject(String bucketName, String objectName)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
(SubResource[]) null);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.DELETE,
null, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.DeleteObject);
processResponse(response, null, "delete object [" + objectName + "] under bucket ["
+ bucketName + "]");
}
@Override
public List<Map<String, Object>> deleteObjects(String bucketName, String prefix)
throws GalaxyFDSClientException {
Preconditions.checkNotNull(bucketName);
Preconditions.checkNotNull(prefix);
List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
FDSObjectListing objects = listObjects(bucketName, prefix, "");
long totalItemsListed = 0, totalItemsDeleted = 0;
int batchDeleteSize = fdsConfig.getMaxBatchDeleteSize();
for (int iterationCnt = 0; objects != null; ++iterationCnt) {
int itemsLeft = objects.getObjectSummaries().size();
totalItemsListed += itemsLeft;
List<String> objectNameList = new ArrayList<String>();
totalItemsDeleted += itemsLeft;
if (itemsLeft > 0)
for (FDSObjectSummary s : objects.getObjectSummaries()) {
String objectName = s.getObjectName();
objectNameList.add(objectName);
--itemsLeft;
if (objectNameList.size() >= batchDeleteSize || itemsLeft <= 0) {
try {
List<Map<String, Object>> errorList = deleteObjects(bucketName, objectNameList);
totalItemsDeleted -= errorList.size();
resultList.addAll(errorList);
} catch (Exception e) {
LOG.warn("fail to delete objects", e);
// retry with small batch size
try {
Thread.sleep(500);
} catch (InterruptedException e1) {
}
for (int index = 0, interval = Math.max(10, objectNameList.size() / 10);
index < objectNameList.size(); ) {
int to = Math.min(index + interval, objectNameList.size());
resultList.addAll(deleteObjects(bucketName,
objectNameList.subList(index, to)));
index = to;
}
}
objectNameList.clear();
}
}
LOG.info("" + iterationCnt + "th round, "
+ " total items listed: " + totalItemsListed
+ " total items deleted: " + totalItemsDeleted
+ " total errors: " + resultList.size());
objects = listNextBatchOfObjects(objects);
}
return resultList;
}
@Override
public List<Map<String, Object>> deleteObjects(String bucketName,
List<String> objectNameList)
throws GalaxyFDSClientException {
Preconditions.checkNotNull(bucketName);
Preconditions.checkNotNull(objectNameList);
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
ContentType contentType = ContentType.APPLICATION_JSON;
StringEntity requestEntity = getJsonStringEntity(objectNameList, contentType);
HashMap<String, String> params = new HashMap<String, String>();
params.put("deleteObjects", "");
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.DeleteObjects);
List<Map<String, Object>> responseList = (List<Map<String, Object>>) processResponse(
response, List.class,
"delete " + objectNameList.size() + " objects under bucket [" + bucketName + "]");
return responseList;
}
@Override
public void restoreObject(String bucketName, String objectName)
throws GalaxyFDSClientException {
ContentType contentType = ContentType.APPLICATION_JSON;
StringEntity requestEntity = getJsonStringEntity("", contentType);
HashMap<String, String> params = new HashMap<String, String>();
params.put("restore", "");
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
(SubResource[]) null);
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.PUT, contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.RestoreObject);
processResponse(response, null,
"restore object [" + objectName + "] under bucket ["
+ bucketName + "]");
}
@Override
public void renameObject(String bucketName, String srcObjectName,
String dstObjectName) throws GalaxyFDSClientException {
ContentType contentType = ContentType.APPLICATION_OCTET_STREAM;
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + srcObjectName,
(SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("renameTo", dstObjectName);
StringEntity requestEntity = getJsonStringEntity("", contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.PUT, contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.RenameObject);
processResponse(response, null, "rename object [" + srcObjectName +
"] to object [" + dstObjectName + "] under bucket [" + bucketName + "]");
}
@Override
public void prefetchObject(String bucketName, String objectName)
throws GalaxyFDSClientException {
ContentType contentType = ContentType.APPLICATION_JSON;
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
(SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("prefetch", "");
StringEntity requestEntity = getJsonStringEntity(null, contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PrefetchObject);
processResponse(response, null, "prefetch object [" + objectName + "] under bucket [" +
bucketName + "]");
}
@Override
public void refreshObject(String bucketName, String objectName)
throws GalaxyFDSClientException {
ContentType contentType = ContentType.APPLICATION_JSON;
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
(SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("refresh", "");
StringEntity requestEntity = getJsonStringEntity(null, contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.RefreshObject);
processResponse(response, null, "refresh object [" + objectName + "] under bucket [" +
bucketName + "]");
}
@Override
public void putDomainMapping(String bucketName, String domainName)
throws GalaxyFDSClientException {
ContentType contentType = ContentType.APPLICATION_JSON;
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName,
(SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("domain", domainName);
StringEntity requestEntity = getJsonStringEntity("", contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutDomainMapping);
processResponse(response, null, "add domain mapping; bucket [" + bucketName
+ "], domainName [" + domainName + "]");
}
@Override
public List<String> listDomainMappings(String bucketName)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("domain", "");
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT, null, null, params, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.ListDomainMappings);
ListDomainMappingsResult result = (ListDomainMappingsResult) processResponse(response,
ListDomainMappingsResult.class,
"list domain mappings; bucket [" + bucketName + "]");
return result.getDomainMappings();
}
@Override
public void deleteDomainMapping(String bucketName, String domainName)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName, (SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("domain", domainName);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.DELETE,
null, null, params, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.DeleteDomainMapping);
processResponse(response, null, "delete domain mapping; bucket [" + bucketName
+ "], domain [" + domainName + "]");
}
public void cropImage(String bucketName, String objectName,
int x, int y, int w, int h)
throws GalaxyFDSClientException {
ContentType contentType = ContentType.APPLICATION_OCTET_STREAM;
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
(SubResource[]) null);
HashMap<String, String> params = new HashMap<String, String>();
params.put("cropImage", "");
params.put("x", Integer.toString(x));
params.put("y", Integer.toString(y));
params.put("w", Integer.toString(w));
params.put("h", Integer.toString(h));
StringEntity requestEntity = getJsonStringEntity("", contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.CropImage);
processResponse(response, null, "crop image; bucket [" + bucketName
+ "], object [" + objectName + "]");
}
@Override
public void setPublic(String bucketName, String objectName)
throws GalaxyFDSClientException {
AccessControlList acl = new AccessControlList();
acl.addGrant(new AccessControlList.Grant(AccessControlList.UserGroups.ALL_USERS.name(), AccessControlList.Permission.READ,
AccessControlList.GrantType.GROUP));
setObjectAcl(bucketName, objectName, acl);
}
@Override
public URI generateDownloadObjectUri(String bucketName, String objectName)
throws GalaxyFDSClientException {
return formatUri(fdsConfig.getDownloadBaseUri(), bucketName + "/"
+ objectName, (SubResource[]) null);
}
@Override
public URI generatePresignedUri(String bucketName, String objectName,
Date expiration) throws GalaxyFDSClientException {
return generatePresignedUri(bucketName, objectName,
expiration, HttpMethod.GET);
}
@Override
public URI generatePresignedCdnUri(String bucketName, String objectName,
Date expiration) throws GalaxyFDSClientException {
return generatePresignedCdnUri(bucketName, objectName,
expiration, HttpMethod.GET);
}
@Override
public URI generatePresignedUri(String bucketName, String objectName,
Date expiration, HttpMethod httpMethod) throws GalaxyFDSClientException {
try {
return generatePresignedUri(fdsConfig.getBaseUri(), bucketName, objectName,
null, null, expiration, httpMethod, credential.getGalaxyAccessId(),
credential.getGalaxyAccessSecret(), SIGN_ALGORITHM);
} catch (GalaxyException e) {
throw new GalaxyFDSClientException(e);
}
}
@Override
public URI generatePresignedCdnUri(String bucketName, String objectName,
Date expiration, HttpMethod httpMethod) throws GalaxyFDSClientException {
try {
return generatePresignedUri(fdsConfig.getCdnBaseUri(), bucketName,
objectName, null, null, expiration, httpMethod, credential.getGalaxyAccessId(),
credential.getGalaxyAccessSecret(), SIGN_ALGORITHM);
} catch (GalaxyException e) {
throw new GalaxyFDSClientException(e);
}
}
@Override
public URI generatePresignedUri(String bucketName, String objectName,
SubResource subResource, Date expiration, HttpMethod httpMethod)
throws GalaxyFDSClientException {
List<String> subResources = new ArrayList<String>();
subResources.add(subResource.getName());
return generatePresignedUri(bucketName, objectName, subResources,
expiration, httpMethod);
}
@Override
public URI generatePresignedUri(String bucketName, String objectName,
List<String> subResources, Date expiration, HttpMethod httpMethod)
throws GalaxyFDSClientException {
try {
return generatePresignedUri(fdsConfig.getBaseUri(), bucketName, objectName,
subResources, null, expiration, httpMethod, credential.getGalaxyAccessId(),
credential.getGalaxyAccessSecret(), SIGN_ALGORITHM);
} catch (GalaxyException e) {
throw new GalaxyFDSClientException(e);
}
}
@Override
public URI generatePresignedUri(String bucketName, String objectName,
List<String> subResources, Date expiration, HttpMethod httpMethod, String contentType)
throws GalaxyFDSClientException {
try {
return generatePresignedUri(fdsConfig.getBaseUri(), bucketName, objectName,
subResources, contentType, expiration, httpMethod, credential.getGalaxyAccessId(),
credential.getGalaxyAccessSecret(), SIGN_ALGORITHM);
} catch (GalaxyException e) {
throw new GalaxyFDSClientException(e);
}
}
@Override
public URI generatePresignedCdnUri(String bucketName, String objectName,
SubResource subResource, Date expiration, HttpMethod httpMethod)
throws GalaxyFDSClientException {
List<String> subResources = new ArrayList<String>();
subResources.add(subResource.getName());
return generatePresignedCdnUri(bucketName, objectName, subResources,
expiration, httpMethod);
}
@Override
public URI generatePresignedCdnUri(String bucketName, String objectName,
List<String> subResources, Date expiration, HttpMethod httpMethod)
throws GalaxyFDSClientException {
try {
return generatePresignedUri(fdsConfig.getCdnBaseUri(), bucketName,
objectName, subResources, null, expiration, httpMethod,
credential.getGalaxyAccessId(), credential.getGalaxyAccessSecret(),
SIGN_ALGORITHM);
} catch (GalaxyException e) {
throw new GalaxyFDSClientException(e);
}
}
@Override
public InitMultipartUploadResult initMultipartUpload(String bucketName,
String objectName) throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
SubResource.UPLOADS);
ContentType contentType = ContentType.APPLICATION_JSON;
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.PUT, contentType, null, null, null, null);
HttpResponse response = executeHttpRequest(httpRequest, Action.InitMultiPartUpload);
InitMultipartUploadResult initMultipartUploadResult = (InitMultipartUploadResult) processResponse(response,
InitMultipartUploadResult.class,
"init multipart upload object [" + objectName +
"] to bucket [" + bucketName + "]");
return initMultipartUploadResult;
}
@Override
public UploadPartResult uploadPart(String bucketName, String objectName,
String uploadId, int partNumber, InputStream in)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
null);
ContentType contentType = ContentType.APPLICATION_OCTET_STREAM;
HashMap<String, String> params = new HashMap<String, String>();
params.put("uploadId", uploadId);
params.put("partNumber", String.valueOf(partNumber));
InputStreamEntity requestEntity = getInputStreamRequestEntity(in, contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.PUT, contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.UploadPart);
UploadPartResult uploadPartResult = (UploadPartResult) processResponse(response,
UploadPartResult.class,
"upload part of object [" + objectName +
"] to bucket [" + bucketName + "]" + "; part number [" +
partNumber + "], upload id [" + uploadId + "]");
return uploadPartResult;
}
@Override
public PutObjectResult completeMultipartUpload(String bucketName,
String objectName, String uploadId, FDSObjectMetadata metadata,
UploadPartResultList uploadPartResultList) throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
null);
ContentType contentType = ContentType.APPLICATION_OCTET_STREAM;
HashMap<String, String> params = new HashMap<String, String>();
params.put("uploadId", uploadId);
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.PUT, contentType, metadata, params, null, null);
HttpResponse response = executeHttpRequest(httpRequest,
Action.CompleteMultiPartUpload);
PutObjectResult putObjectResult = (PutObjectResult) processResponse(response,
PutObjectResult.class,
"complete multipart upload of object [" + objectName +
"] to bucket [" + bucketName + "]" + "; upload id [" + uploadId + "]");
return putObjectResult;
}
@Override
public void abortMultipartUpload(String bucketName, String objectName,
String uploadId) throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), bucketName + "/" + objectName,
null);
ContentType contentType = ContentType.APPLICATION_JSON;
HashMap<String, String> params = new HashMap<String, String>();
params.put("uploadId", uploadId);
HttpUriRequest httpRequest = prepareRequestMethod(uri,
HttpMethod.DELETE, contentType, null, params, null, null);
HttpResponse response = executeHttpRequest(httpRequest,
Action.AbortMultiPartUpload);
processResponse(response, null,
"abort multipart upload of object [" + objectName +
"] to bucket [" + bucketName + "]" +
"; upload id [" + uploadId + "]");
}
/**
* Put client metrics to server. This method should only be used internally.
*
* @param clientMetrics Metrics to be pushed to server.
* @throws GalaxyFDSClientException
*/
public void putClientMetrics(ClientMetrics clientMetrics)
throws GalaxyFDSClientException {
URI uri = formatUri(fdsConfig.getBaseUri(), "", (SubResource[]) null);
ContentType contentType = ContentType.APPLICATION_JSON;
HashMap<String, String> params = new HashMap<String, String>();
params.put("clientMetrics", "");
HttpEntity requestEntity = getJsonStringEntity(clientMetrics, contentType);
HttpUriRequest httpRequest = prepareRequestMethod(uri, HttpMethod.PUT,
contentType, null, params, null, requestEntity);
HttpResponse response = executeHttpRequest(httpRequest, Action.PutClientMetrics);
processResponse(response, null, "put client metrics");
}
private StringEntity getJsonStringEntity(Object entityContent, ContentType mediaType) {
Gson gson = new Gson();
String jsonStr = "";
if (entityContent != null) {
jsonStr = gson.toJson(entityContent);
}
StringEntity entity = new StringEntity(jsonStr, mediaType);
return entity;
}
private InputStreamEntity getInputStreamRequestEntity(InputStream input,
ContentType contentType) {
return getInputStreamRequestEntity(input, contentType, -1/* unknown length*/);
}
private InputStreamEntity getInputStreamRequestEntity(InputStream input,
ContentType contentType, long inputStreamLength) {
BufferedInputStream bufferedInputStream = new BufferedInputStream(input);
InputStreamEntity entity = new InputStreamEntity(bufferedInputStream,
inputStreamLength, contentType);
return entity;
}
URI formatUri(String baseUri,
String resource, SubResource... subResourceParams)
throws GalaxyFDSClientException {
String subResource = null;
if (subResourceParams != null) {
for (SubResource param : subResourceParams) {
if (subResource != null) {
subResource += "&" + param.getName();
} else {
subResource = param.getName();
}
}
}
try {
URI uri = new URI(baseUri);
String schema = uri.getScheme();
String host = uri.getHost();
int port = uri.getPort();
URI encodedUri;
if (subResource == null) {
encodedUri = new URI(schema, null, host, port, "/" + resource,
null, null);
} else {
encodedUri = new URI(schema, null, host, port, "/" + resource,
subResource, null);
}
return encodedUri;
} catch (URISyntaxException e) {
LOG.error("Invalid uri syntax", e);
throw new GalaxyFDSClientException("Invalid uri syntax", e);
}
}
Map<String, Object> prepareRequestHeader(URI uri,
HttpMethod method, ContentType contentType, FDSObjectMetadata metadata)
throws GalaxyFDSClientException {
LinkedListMultimap<String, String> headers = LinkedListMultimap.create();
if (metadata != null) {
for (Map.Entry<String, String> e : metadata.getRawMetadata().entrySet()) {
headers.put(e.getKey(), e.getValue());
}
}
// Format date
String date = DATE_FORMAT.format(new Date());
headers.put(Common.DATE, date);
// Set content type
if (contentType != null)
headers.put(Common.CONTENT_TYPE, contentType.toString());
// Set unique request id
headers.put(XiaomiHeader.REQUEST_ID.getName(), getUniqueRequestId());
// Set authorization information
String signature;
try {
URI relativeUri = new URI(uri.toString().substring(
uri.toString().indexOf('/', uri.toString().indexOf(':') + 3)));
signature = Signer.signToBase64(method, relativeUri, headers,
credential.getGalaxyAccessSecret(), SIGN_ALGORITHM);
} catch (InvalidKeyException e) {
LOG.error("Invalid secret key spec", e);
throw new GalaxyFDSClientException("Invalid secret key sepc", e);
} catch (NoSuchAlgorithmException e) {
LOG.error("Unsupported signature algorithm:" + SIGN_ALGORITHM, e);
throw new GalaxyFDSClientException("Unsupported signature slgorithm:"
+ SIGN_ALGORITHM, e);
} catch (Exception e) {
throw new GalaxyFDSClientException(e);
}
String authString = "Galaxy-V2 " + credential.getGalaxyAccessId() + ":"
+ signature;
headers.put(Common.AUTHORIZATION, authString);
Map<String, Object> httpHeaders = new HashMap<String, Object>();
for (Entry<String, String> entry : headers.entries()) {
httpHeaders.put(entry.getKey(), entry.getValue());
}
return httpHeaders;
}
AccessControlList acpToAcl(AccessControlPolicy acp) {
AccessControlList acl = null;
if (acp != null) {
acl = new AccessControlList();
for (GrantBean g : acp.getAccessControlList()) {
acl.addGrant(new AccessControlList.Grant(g.getGrantee().getId(),
g.getPermission(), g.getType()));
}
}
return acl;
}
AccessControlPolicy aclToAcp(AccessControlList acl) {
AccessControlPolicy acp = null;
if (acl != null) {
acp = new AccessControlPolicy();
acp.setOwner(new OwnerBean(credential.getGalaxyAccessId()));
List<GrantBean> grants = new ArrayList<GrantBean>(
acl.getGrantList().size());
for (AccessControlList.Grant g : acl.getGrantList()) {
grants.add(new GrantBean(new GranteeBean(g.getGranteeId()),
g.getPermission(), g.getType()));
}
acp.setAccessControlList(grants);
}
return acp;
}
FDSObjectListing getObjectListing(ListObjectsResult result) {
FDSObjectListing listing = null;
if (result != null) {
listing = new FDSObjectListing();
listing.setBucketName(result.getName());
listing.setPrefix(result.getPrefix());
listing.setDelimiter(result.getDelimiter());
listing.setMarker(result.getMarker());
listing.setNextMarker(result.getNextMarker());
listing.setMaxKeys(result.getMaxKeys());
listing.setTruncated(result.isTruncated());
List<FDSObjectSummary> summaries = new ArrayList<FDSObjectSummary>(
result.getObjects().size());
for (ObjectBean o : result.getObjects()) {
FDSObjectSummary summary = new FDSObjectSummary();
summary.setBucketName(result.getName());
summary.setObjectName(o.getName());
summary.setSize(o.getSize());
summary.setOwner(new Owner(o.getOwner().getId(),
o.getOwner().getDisplayName()));
summaries.add(summary);
}
listing.setObjectSummaries(summaries);
listing.setCommonPrefixes(result.getCommonPrefixes());
}
return listing;
}
private String getUniqueRequestId() {
return clientId + "_" + random.nextInt();
}
private String formatErrorMsg(String purpose, Exception e) {
String msg = "failed to " + purpose + ", " + e.getMessage();
return msg;
}
private String formatErrorMsg(String purpose, HttpResponse response) {
String msg = "failed to " + purpose + ", status=" +
response.getStatusLine().getStatusCode() +
", reason=" + getResponseEntityPhrase(response);
return msg;
}
void closeInputStream(InputStream inputStream) throws GalaxyFDSClientException {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
String errorMsg = "close file input stream failed";
LOG.error(errorMsg);
throw new GalaxyFDSClientException(errorMsg, e);
}
}
}
private static URI generatePresignedUri(String baseUri, String bucketName,
String objectName, List<String> subResources, String contentType, Date expiration,
HttpMethod httpMethod, String accessId, String accessSecret,
SignAlgorithm signAlgorithm) throws GalaxyException{
try {
URI uri = new URI(baseUri);
URI encodedUri;
if (subResources == null || subResources.isEmpty()) {
encodedUri = new URI(uri.getScheme(), null, uri.getHost(),
uri.getPort(), "/" + bucketName + "/" + objectName,
Common.GALAXY_ACCESS_KEY_ID + "=" + accessId
+ "&" + Common.EXPIRES + "=" + expiration.getTime(), null);
} else {
encodedUri = new URI(uri.getScheme(), null, uri.getHost(),
uri.getPort(), "/" + bucketName + "/" + objectName,
StringUtils.join(subResources, "&") + "&" +
Common.GALAXY_ACCESS_KEY_ID + "=" + accessId
+ "&" + Common.EXPIRES + "=" + expiration.getTime(), null);
}
LinkedListMultimap<String, String> headers = null;
if (contentType != null && !contentType.isEmpty()) {
headers = LinkedListMultimap.create();
headers.put(Common.CONTENT_TYPE, contentType);
}
String signature = Signer.signToBase64(httpMethod, encodedUri, headers,
accessSecret, signAlgorithm);
return new URI(encodedUri.toString() + "&" + Common.SIGNATURE + "="
+ new String(signature));
} catch (URISyntaxException e) {
LOG.error("Invalid URI syntax", e);
throw new GalaxyException("Invalid URI syntax", e);
} catch (InvalidKeyException e) {
LOG.error("Invalid secret key spec", e);
throw new GalaxyException("Invalid secret key spec", e);
} catch (NoSuchAlgorithmException e) {
LOG.error("Unsupported signature algorithm:" + signAlgorithm, e);
throw new GalaxyException("Unsupported signature algorithm:"
+ signAlgorithm, e);
}
}
private LinkedListMultimap<String, String> headerArray2MultiValuedMap(Header[] headers) {
LinkedListMultimap<String, String> m = LinkedListMultimap.create();
if (headers != null)
for (Header h: headers) {
m.put(h.getName(), h.getValue());
}
return m;
}
}